﻿using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace UnityExtensions
{
	/// <summary>
	/// ScriptableObject的拓展工具集
	/// </summary>
	public static class ScriptableUtility
	{
		/// <summary>
		/// create instance defalt name type name
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <returns></returns>
		public static T CreateInstance<T>() where T:ScriptableObject
		{
			T t = ScriptableObject.CreateInstance<T>();
			t.name = t.GetType().Name;
			return t;
		}
		/// <summary>
		/// 根据参数传入的类型创建实例并转换成对应T类型
		/// </summary>
		/// <typeparam name="T">需要转换的类型</typeparam>
		/// <param name="tp">需要实例的类型</param>
		/// <returns></returns>
		public static T CreateInstance<T>(System.Type tp) where T:ScriptableObject
		{
			T ins = ScriptableObject.CreateInstance(tp) as T;
			ins.name = tp.Name;
			return ins;
		}
		/// <summary>
		/// 深度拷贝一个ScripableObject的派生类
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="original"></param>
		/// <returns></returns>
		public static T Instantiate<T>(T original) where T:ScriptableObject
		{
			ScriptableObject s = ScriptableUtility.Instantiate0(original);
			T t = s as T;
			return t;
		}
		public static ScriptableObject Instantiate0(ScriptableObject original)
		{
			List<ScriptableObject> scrips = new List<ScriptableObject>();
			scrips.Add(original);
			ReflectionUtility.GetAllReferenceInstance<ScriptableObject>(scrips,original,true);
			List<ScriptableObject> scrips1 = new List<ScriptableObject>(scrips.Count);
			scrips.ForEach(item =>
			{
				ScriptableObject scri = ScriptableObject.Instantiate<ScriptableObject>(item);
				//DebugE.Log("{0},{1} Instantiate {2},{3}",item.name,item.GetInstanceID(),scri.name,scri.GetInstanceID());
				scrips1.Add(scri);
			});
			Type scripType = typeof(ScriptableObject);
			for(int i = 0,length = scrips1.Count;i < length;i++)
			{
				ScriptableObject item1 = scrips1[i];
				FieldInfo[] fields = item1.GetType().GetSerializeFields(true);
				int i1 = 0;
				for(;i1 < fields.Length;i1++)
				{
					FieldInfo field = fields[i1];
					Type fieldType = field.FieldType;
					#region 如果是类
					if(fieldType.IsSubclassOf(scripType))
					{
						ScriptableObject item = scrips[i];
						System.Object ovalue = field.GetValue(item);
						if(ovalue != null)
						{
							ScriptableObject svalue = ovalue as ScriptableObject;
							int index = scrips.IndexOf(svalue);
							ScriptableObject newvalue = scrips1[index];
							field.SetValue(item1,newvalue);
#if false
						DebugE.Log("深度拷贝{0},{1}的{2}= >{3}={4}",
							item1,item1.GetInstanceID(),
							field.Name,
							svalue.GetInstanceID(),
							newvalue.GetInstanceID());
#endif
						}
					}
					#endregion
					#region 如果是泛型list
					else if(fieldType.IsGenericType)
					{
						Type listyp = typeof(List<>);
						Type genericType = fieldType.GetGenericTypeDefinition();
						if(listyp == genericType)
						{
							Type[] listargTypes = fieldType.GetGenericArguments();
							foreach(var item2 in listargTypes)
							{
								if(item2.IsSubclassOf(typeof(ScriptableObject)))
								{
									ScriptableObject item = scrips[i];
									System.Object obj = field.GetValue(item);
									IList vlist = obj as IList;
									System.Object newObj = Activator.CreateInstance(fieldType);
									IList newList = newObj as IList;
									foreach(var item11 in vlist)
									{
										ScriptableObject svalue = item11 as ScriptableObject;
										if(svalue != null)
										{
											int index2 = scrips.IndexOf(svalue);
											ScriptableObject newvalue = scrips1[index2];
											newList.Add(newvalue);
#if false
										DebugE.Log("深度拷贝{0},{1}的{2}= >{3}={4}",
											item1,item1.GetInstanceID(),
											field.Name,
											svalue.GetInstanceID(),
											newvalue.GetInstanceID());
#endif
										}
									}
									field.SetValue(item1,newList);
								}
							}
						}
					}
					#endregion
				}
			}
			for(int i = 0,length = scrips.Count;i < length;i++)
			{
				scrips1[i].name = scrips[i].name;
			}
			return scrips1[0];
		}
	}
}
